﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Printing;
using System.Windows;
using System.Windows.Input;
using personalplaner.business;
using personalplaner.business.dienstplan;
using personalplaner.business.dienstplan.plancollection;
using personalplaner.common.extensions;
using personalplaner.common.mvvm;
using personalplaner.common.mvvm.commands;
using personalplaner.servicemodel.dataaccess;
using personalplaner.business.enums;

namespace personalplaner.gui.plugins.dienstplan.viewmodels
{
	public class PrintViewViewModel : BaseViewModel
	{
		public PrintViewViewModel(DependencyObject parent)
            : base(parent)
        {
        }

		public override void Loaded()
		{
			var da = GetService<IOptionsDataAccess>();

			PrintSaldoDifference = da.PrintSaldoDifference;
			PrintSoll = da.PrintSoll;
			PrintHaben = da.PrintHaben;
			ShowPensumInPlan = da.ShowPensumInPlan;

			var mw = GetService<IMainWindowDisplayContainer>();
			mw.IsWaitVisible = false;
		}

		#region Implementation

		private void SetupPages(DienstPlanCollection plan)
		{
			if (plan == null)
				return;

			//Pages.Clear();
			var pages = new ObservableCollection<DienstPlanCollection>();

			// 35 rows + header (20) when rowheight = 19
			// 37 rows + header (20) when rowheight = 18
			const int rowcount = 37;

			if (SelectedTeam.AbteilungId == -1)
			{
				//TODO: create setting if each team should be on a separate page
				if (plan.Count > rowcount)
				{
					// use a new page for every team
					var teams = (from a in Plan where a is AbteilungRow select new DienstPlanRowHeader { Name = a.Name, AbteilungId = a.AbteilungId }).ToList();
					foreach (var team in teams)
					{
						var lst = (from a in plan where a.AbteilungId == team.AbteilungId select a).ToList();
						if (lst.Count > rowcount)
						{
							// split the list up to fit onto the page resp. create multiple pages
							var dayrow = (from a in lst where a is DayHeaderRow select a).FirstOrDefault() as DayHeaderRow;
							var tmplst = (from a in lst where !(a is DayHeaderRow) select a).ToList();

							var da = GetService<IOptionsDataAccess>();

							while (tmplst.Count > 0)
							{
								var newlst = new DienstPlanCollection();
								if (da.ShowDaysInPlan && dayrow != null)
								{
									newlst.Add(dayrow);
								}

								while (tmplst.Count > 0)
								{
									var itm = tmplst[0];
									tmplst.Remove(itm);
									newlst.Add(itm);

									if (newlst.Count == rowcount)
										break;
								}
								pages.Add(newlst);
							}

						}
						else
							pages.Add(new DienstPlanCollection(lst));
					}
				}
				else
					pages.Add(plan);
			}
			else
			{
				var lst = (from a in plan where a.AbteilungId == SelectedTeam.AbteilungId select a).ToList();

				if (lst.Count > rowcount)
				{
					// split the list up to fit onto the page resp. create multiple pages
					var dayrow = (from a in lst where a is DayHeaderRow select a).FirstOrDefault() as DayHeaderRow;
					var tmplst = (from a in lst where !(a is DayHeaderRow) select a).ToList();

					var da = GetService<IOptionsDataAccess>();

					while (tmplst.Count > 0)
					{
						var newlst = new DienstPlanCollection();
						if (da.ShowDaysInPlan && dayrow != null)
						{
							newlst.Add(dayrow);
						}

						while (tmplst.Count > 0)
						{
							var itm = tmplst[0];
							tmplst.Remove(itm);
							newlst.Add(itm);

							if (newlst.Count == rowcount)
								break;
						}
						pages.Add(newlst);
					}
				}
				else
					pages.Add(new DienstPlanCollection(lst));
			}

			this.Pages = pages;
		}

		#endregion
		
		#region Commands

		ICommand _okcommand;
		public ICommand OkCommand
		{
			get
			{
				if (_okcommand == null)
					_okcommand = new RelayCommand(OnOkCommand);
				return _okcommand;
			}
		}

		private void OnOkCommand(object parameter)
		{
			//// use mediator to notify all suscribed methods that the list of plans has to be refreshed
			//Mediator.NotifyColleagues("RefreshPlanList");

			var wnd = Parent as Window;
			if (wnd != null)
			{
				wnd.DialogResult = true;
				wnd.Close();
				return;
			}

			var mw = GetService<IMainWindowDisplayContainer>();
			mw.MoveToPreviousView();
		}

		ICommand _cancelcommand;
		public ICommand CancelCommand
		{
			get
			{
				if (_cancelcommand == null)
					_cancelcommand = new RelayCommand(OnCancelCommand);
				return _cancelcommand;
			}
		}

		private void OnCancelCommand(object parameter)
		{
			var wnd = Parent as Window;
			if (wnd != null)
			{
				wnd.DialogResult = false;
				wnd.Close();
				return;
			}

			var mw = GetService<IMainWindowDisplayContainer>();
			mw.MoveToPreviousView();
		}

		ICommand _printcommand;
		public ICommand PrintCommand
		{
			get
			{
				if (_printcommand == null)
					_printcommand = new RelayCommand(OnPrint);
				return _printcommand;
			}
		}

		private void OnPrint(object parameter)
		{
			//System.Windows.Documents.DocumentPaginator
			//http://www.eggheadcafe.com/tutorials/aspnet/9cbb4841-8677-49e9-a3a8-46031e699b2e/wpf-printing-and-print-preview.aspx
            //http://blogs.msdn.com/b/fyuan/archive/2007/03/10/convert-xaml-flow-document-to-xps-with-style-multiple-page-page-size-header-margin.aspx
            //http://www.switchonthecode.com/tutorials/printing-in-wpf


            //http://msdn.microsoft.com/en-us/library/ms748373.aspx

			var pdlg = new System.Windows.Controls.PrintDialog();
			//pdlg.ShowDialog();

            SelectedPrinter.DefaultPrintTicket.CopyCount = Copies;
            SelectedPrinter.CurrentJobSettings.CurrentPrintTicket.CopyCount = Copies;

			pdlg.PrintQueue = SelectedPrinter;

            var p = Parent as personalplaner.gui.plugins.dienstplan.views.PrintView;
			if (p == null)
				throw new Exception("The Parent Control should be a PrintView");

			//pdlg.PrintVisual(p.PrintPreview.SelectedContentPresenter, Plan.Name);
			pdlg.PrintDocument(p.PrintPreview.GetDocumentPaginator(), Plan.Name);
		}

		#endregion

		#region Properties

		DienstPlanCollection _plan;
		public DienstPlanCollection Plan
		{
			get { return _plan; }
			set
			{
				_plan = value;
				RaisePropertyChanged("Plan");
				RaisePropertyChanged("Teams");

				SetupPages(value);
			}
		}

        IList<DienstPlanCollection> _pages;
        public IList<DienstPlanCollection> Pages
        {
            get
            {
                return _pages;
			}
			set
			{
				_pages = value;
				RaisePropertyChanged("Pages");
			}
        }

		int _copies = 1;
		public int Copies
		{
			get { return _copies; }
			set
			{
				_copies = value;
				RaisePropertyChanged("Copies");
			}
		}

		public IList<DienstPlanRowHeader> Teams
		{
			get
			{
				if (Plan == null)
					return null;

				var lst = (from a in Plan where a is AbteilungRow select new DienstPlanRowHeader { Name = a.Name, AbteilungId = a.AbteilungId }).ToList();

				if (lst == null)
					lst = new List<DienstPlanRowHeader>();

				lst.Insert(0, new DienstPlanRowHeader { Name = "Alle", AbteilungId = -1 });
				
				// don't set the selected team with the property set because of the redudant call of SetupPages(...) in the seter
				_selectedTeam = lst[0];
				RaisePropertyChanged("SelectedTeam");

				return lst;
			}
		}

		DienstPlanRowHeader _selectedTeam;
		public DienstPlanRowHeader SelectedTeam
		{
			get { return _selectedTeam; }
			set
			{
				_selectedTeam = value;
				RaisePropertyChanged("SelectedTeam");

				if (Plan != null)
					SetupPages(Plan);
			}
		}

        IList<string> _nameDisplayOptions;
        public IList<string> NameDisplayOptions
        {
            get
            {
                if (_nameDisplayOptions == null)
                {
                    _nameDisplayOptions = new List<string>
                    {
                        Properties.Resources.PrintVornameName,
                        Properties.Resources.PrintNameVorname,
                        Properties.Resources.PrintNameV,
                        Properties.Resources.PrintName
                    };
                }
                return _nameDisplayOptions;
            }
        }

        string _selectedNameDisplayOption;
        public string SelectedNameDisplayOption
        {
            get
            {
                if (string.IsNullOrEmpty(_selectedNameDisplayOption))
                {
                    var da = GetService<IOptionsDataAccess>();
                    _selectedNameDisplayOption = NameDisplayOptions[(int)da.NameDisplayOption];
                }
                return _selectedNameDisplayOption;
            }
            set
            {
                _selectedNameDisplayOption = value;
                Mediator.NotifyColleagues("SelectedNameDisplayOption");


                int index = NameDisplayOptions.IndexOf(value);

                foreach (var page in Pages)
                {
                    foreach (var row in page)
                    {
                        var itm = row as PersonRow;
                        if (itm == null)
                            continue;

                        switch (index)
                        {
                            case 0:
                                row.Name = string.Format("{0} {1}", itm.Vorname, itm.Nachname);
                                break;
                            case 1:
                                row.Name = string.Format("{0} {1}", itm.Nachname, itm.Vorname);
                                break;
                            case 2:
                                row.Name = string.Format("{0} {1}.", itm.Nachname, itm.Vorname.Substring(0, 1));
                                break;
                            case 3:
                                row.Name = itm.Nachname;
                                break;
                        }
                    }
                }
            }
        }

        bool _printSaldoDifference;
		public bool PrintSaldoDifference
		{
			get
			{
				return _printSaldoDifference;
			}
			set
			{
				_printSaldoDifference = value;
				RaisePropertyChanged("PrintSaldoDifference");
			}
		}

		bool _printSoll;
		public bool PrintSoll
		{
			get
			{
				return _printSoll;
			}
			set
			{
				_printSoll = value;
				RaisePropertyChanged("PrintSoll");
			}
		}

		bool _printHaben;
		public bool PrintHaben
		{
			get
			{
				return _printHaben;
			}
			set
			{
				_printHaben = value;
				RaisePropertyChanged("PrintHaben");
			}
		}

		bool _showPensumInPlan;
		public bool ShowPensumInPlan
		{
			get
			{
				return _showPensumInPlan;
			}
			set
			{
				_showPensumInPlan = value;
				RaisePropertyChanged("ShowPensumInPlan");
			}
		}

		double _rowheight = 18;
		public double RowHeight
		{
			get
			{
				return _rowheight;
			}
			set
			{
				_rowheight = value;
				RaisePropertyChanged("RowHeight");
			}
		}

		#region PrinterSettings

		//private Dictionary<string, BitmapSource> _systemIcons;
		//public Dictionary<string, BitmapSource> SystemIcons
		//{
		//    get
		//    {
		//        if (_systemIcons == null)
		//        {
		//            _systemIcons = personalplaner.common.utilities.SystemIconHelper.SystemIcons;
		//        }

		//        return _systemIcons;
		//    }
		//}

		List<PrintQueue> _printers;
		public List<PrintQueue> Printers
		{
			get
			{
				if (_printers == null)
				{
					_printers = new List<PrintQueue>();

					var printServer = new LocalPrintServer();
					var printQueuesOnLocalServer = printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections });
					foreach (PrintQueue printer in printQueuesOnLocalServer)
					{
						_printers.Add(printer);
					}
				}

				var dp = LocalPrintServer.GetDefaultPrintQueue();
				foreach (var pq in _printers)
				{
					//try
					//{
					//    var tmp = personalplaner.common.utilities.SystemIconHelper.ExtractAssociatedIcon(pq.FullName);
					//}
					//catch
					//{
					//}

					//Console.WriteLine(pq.QueueStatus);
					//Console.WriteLine(pq.Location);
					//Console.WriteLine(pq.HostingPrintServer);

					if (pq.Name == dp.Name)
					{
						SelectedPrinter = pq;
						break;
					}
				}
				return _printers;
			}
		}

		PrintQueue _selectedPrinter;
		public PrintQueue SelectedPrinter
		{
			get { return _selectedPrinter; }
			set
			{
				_selectedPrinter = value;
				RaisePropertyChanged("SelectedPrinter");

				value.CurrentJobSettings.CurrentPrintTicket.PageOrientation = PageOrientation.Landscape;
				value.DefaultPrintTicket.PageOrientation = PageOrientation.Landscape;

				RaisePropertyChanged("PaperWidth");
				RaisePropertyChanged("PaperHeight");
			}
		}

		public double? PaperWidth
		{
			get
			{
				if (SelectedPrinter.DefaultPrintTicket.PageOrientation == PageOrientation.Landscape)
					return SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height;

				return SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width;
			}
		}

		public double? PaperHeight
		{
			get
			{
				if (SelectedPrinter.DefaultPrintTicket.PageOrientation == PageOrientation.Landscape)
					return SelectedPrinter.DefaultPrintTicket.PageMediaSize.Width;

				return SelectedPrinter.DefaultPrintTicket.PageMediaSize.Height;
			}
		}


		#endregion

		#endregion
	}
}
